#include<stdio.h>

#include "include/Arcroll.h"
#include<Mesh_IO/Mesh_IO.h>
#include<tool/libcell_tools_io.h>
#include<points_cloud_algorithm.h>
#include<Mesh/lib_cell_iterator.h>
#define Matrix4x4 Viewer_Matrix4x4_
#define quote lib_cell_quote
static inline bool test_make_up_points_is_boundary(float* re,int x,int y,int x_times,int y_times)
{
    if(x<0||y<0||re[y*x_times+x]>0)
    {
        return false;
    }
    int indexs[8][2]={{x-1,y-1},{x,y-1},{x+1,y-1},{x-1,y},{x+1,y},{x-1,y+1},{x,y+1},{x+1,y+1}};

    for(int i=0;i<8;i++)
    {
        if(indexs[i][0]>=0&&indexs[i][0]<x_times&&indexs[i][1]>=0&&indexs[i][1]<y_times)
        {
            if(re[indexs[i][1]*x_times+indexs[i][0]]>0)
            {
                return true;
            } 
        }
    }
    return false;    
} 

static inline void test_make_up_one_points(float* re,int x,int y,int x_times,int y_times)
{
     int indexs[8][2]={{x-1,y-1},{x,y-1},{x+1,y-1},{x-1,y},{x+1,y},{x-1,y+1},{x,y+1},{x+1,y+1}};
    //re[y*x_times+x]=0;
    
    float temp=0;int temp_sum=0;  
    for(int i=0;i<8;i++)
    {
        if(indexs[i][0]>=0&&indexs[i][0]<x_times&&indexs[i][1]>=0&&indexs[i][1]<y_times)
        {
            if(re[indexs[i][1]*x_times+indexs[i][0]]>0)
            {
                temp+=re[indexs[i][1]*x_times+indexs[i][0]];

                temp_sum++;       
            } 
        }
    }
    if(temp_sum>0)
    {
        re[y*x_times+x]=temp/((float)temp_sum);
    }
    // else
    // {
    //     printf("cuowu\n");
    // }
}
static inline void test_make_up_point_find_next_boundary(float* re,int *x_b,int *y_b,int x_times,int y_times)
{
    int x=*x_b,y=*y_b;
    int indexs[8][2]={{x-1,y-1},{x,y-1},{x+1,y-1},{x-1,y},{x+1,y},{x-1,y+1},{x,y+1},{x+1,y+1}};
    for(int i=0;i<8;i++)
    {
        if(indexs[i][0]>=0&&indexs[i][0]<x_times&&indexs[i][1]>=0&&indexs[i][1]<y_times)
        {
            if(re[indexs[i][1]*x_times+indexs[i][0]]<0)
            {
                *x_b=indexs[i][0];*y_b=indexs[i][1];
                return;
                //return true;
            } 
        }
    }
    *x_b=-1;*y_b=-1;
}

//make up matrix or image
void test_make_up_matrix(float* re,int x_times,int y_times)
{

//make up
    int make_up=1;
    do{
        int x_b=-1,y_b=-1;
// find start point's index
        for(int i=0;i<x_times;i++)
        {
            for(int j=0;j<y_times;j++)
            {
                if(test_make_up_points_is_boundary(re,i,j,x_times,y_times))
                {
                    x_b=i;y_b=j;
                    break;
                }

            }
        } 
        if(x_b<=-1||y_b<=-1)
        {
            break;
        } 
       //depth first
        while(x_b>=0&&y_b>=0)
        {
          //  printf("%d %d %lf\n",x_b,y_b,re[y_b*x_times+x_b] );
            test_make_up_one_points(re,x_b,y_b,x_times,y_times);

            test_make_up_point_find_next_boundary(re,&x_b,&y_b,x_times,y_times);
          
        }    



    } while(make_up);
   // printf("make up:%d\n",make_up );

}
//this function is for zkhy
void test_make_up_matrix1(float* re,int x_times,int y_times)
{

   for(int i=0;i<x_times;i++)
   {
        for (int j = 0; j < y_times; j++)
        {
            test_make_up_one_points(re,i,j,x_times,y_times); 
        }
   } 

}

float* test_make_up_points(Mesh* mesh,float x_min,float x_max,float y_min,float y_max,int x_times,int y_times)
{
    //make up points
   // Mesh mesh;
    //Mesh_init(&mesh);
    //_Read_(mesh,filename);

    float *re=(float*)malloc(sizeof(float)*x_times*y_times);
    memset(re,0,sizeof(float)*x_times*y_times);
    Node** ren=(Node**)malloc(sizeof(Node*)*x_times*y_times);
    memset(ren,0,sizeof(Node*)*x_times*y_times);

    float x_step=(x_max-x_min)/(float)x_times,y_step=(y_max-y_min)/(float)y_times;

//    Node* node=NULL;
    int mynums=0;
    for(auto vit=mesh->v_begin(mesh);vit!=mesh->v_end(mesh);vit++)
    {
        int x=0,y=0;
        if(quote(vit)->point[0]>x_min&&quote(vit)->point[0]<x_max&&quote(vit)->point[1]>y_min&&quote(vit)->point[1]<y_max)
        {   
            mynums++;
            x=(int)((quote(vit)->point[0]-x_min)/x_step);
            if(x>=x_times)
            {
                x--;
            }
            y=(int)((quote(vit)->point[1]-y_min)/y_step);
            if(y>=y_times)
            {
                y--;
            }

            ren[y*x_times+x]=node_overlying(ren[y*x_times+x],quote(vit)); 
        }
    }

    for(int i=0;i<x_times;i++)
    {
        for(int j=0;j<y_times;j++)
        {
            float temp_num=0;
            for(Node *nit=ren[j*x_times+i];nit!=NULL;nit=(Node*)(nit->Next))
            {
                template_v* v=(template_v*)(nit->value);
                re[j*x_times+i]+=v->point[2];
                temp_num=temp_num+1; 
            } 
            if(temp_num>0)
            {
                re[j*x_times+i]/=temp_num;
                //printf("%lf\n",re[j*x_times+i] );
            }
            else
            {

                re[j*x_times+i]=-1.1;
               
            }
        }
    }

    test_make_up_matrix1(re,x_times,y_times); 
    test_make_up_matrix(re,x_times,y_times); 
//write 
#ifdef _WIN32
    FILE* infile;
    fopen_s(&infile,"make_up.obj","w");
#else
    FILE *infile=fopen("make_up.obj","w");
#endif
    //int mesh_num=0;
    for(int i=0;i<x_times;i++)
    {   
        for(int j=0;j<y_times;j++)
        {
            if(re[j*x_times+i]>0)
            {
                fprintf(infile, "v %lf %lf %lf\n",(float)(i*x_step+x_min),(float)(j*y_step+y_min),re[j*x_times+i] );
                //mesh_num++;
            }
        }
    } 
    fclose(infile);
 





     


    //visual
    Viewer_World_Manager *vwm=(Viewer_World_Manager*)malloc(sizeof(Viewer_World_Manager));
    viewer_world_manager_init(vwm);
    Viewer_World *vw=vwm->create_world(vwm,NULL);
    char camera[]="Camera";
    Node* n=vw->create_something(vw,camera);
    Viewer_Something* ms=(Viewer_Something*)(n->value);
    Viewer_Camera*mc=(Viewer_Camera*)(ms->evolution);
    mc->is_using=1;
    Matrix4x4 *p=Projection(M_PI/3.0f,(float)(vw->g_info->resolution[0])/(float)(vw->g_info->resolution[1]),0.5f,200.0f);
    p->copy_data(mc->Proj,p);
    Matrix4x4_free(p);
    free_node(n);
    char intera[]="Intera";
    n=vw->create_something(vw,intera);
    ms=(Viewer_Something*)(n->value);
    Viewer_Intera* mi=(Viewer_Intera*)(ms->evolution);
    Viewer_Arcroll *ma=(Viewer_Arcroll*)malloc(sizeof(Viewer_Arcroll));
    Viewer_Arcroll_init(ma);
    ma->mc=mc;
    ma->vw=vw;
    mi->representation=ma;
    mi->scroll_callback=viewer_Arcroll_scroll_callback;
    mi->drop_callback=viewer_Arcroll_drop_callback;
    mi->cursor_position_callback=viewer_Arcroll_cursor_position_callback; 
    free_node(n); 
    char points[]="Points";
    n=vw->create_something(vw,points);
    ms=(Viewer_Something*)(n->value);
    Viewer_Points* vp=(Viewer_Points*)(ms->evolution);
    //vp->Data_rows=mesh.num_v(&mesh);
    vp->Data_rows=x_times*y_times;
    //vp->Data_rows=mynums;
   vp->pointsize=5.0;
    vp->Data=(float*)malloc(sizeof(float)*3*vp->Data_rows);
    memset(vp->Data,0,sizeof(float)*3*vp->Data_rows);
    int ii=0;

    for(int i=0;i<x_times;i++)
    {
        for(int j=0;j<y_times;j++)
        {
            // for(Node *nit=ren[j*x_times+i];nit!=NULL;nit=(Node*)(nit->Next))
            // {
            //     template_v* v=(template_v*)(nit->value);
            //     vp->Data[ii]=v->point[0]; 
            //     ii++;
            //     vp->Data[ii]=v->point[1];
            //     ii++;
            //     vp->Data[ii]=v->point[2];
            //     ii++;
            // } 
            vp->Data[ii]=(float)(i*x_step);
            ii++;
            vp->Data[ii]=(float)(j*y_step);
            ii++;
            vp->Data[ii]=re[j*x_times+i];
            ii++;
        }
    }
   
    srand((unsigned)time(NULL));
    float colors[4]={(rand()%100)/100.0,(rand()%100)/100.0,(rand()%100)/100.0,1};
    vp->set_color(vp,colors);  



    Viewer_Opengl_Interpreter* voi=(Viewer_Opengl_Interpreter*)malloc(sizeof(Viewer_Opengl_Interpreter));
    viewer_opengl_interpreter_initn(voi,vwm);
    ma->voi=voi;
    voi->interpreter(voi);
    viewer_opengl_interpreter_free(voi); 


// visual 
   // Mesh_free(&mesh);
    for(int i=0;i<x_times;i++)
    {
        for(int j=0;j<y_times;j++)
        {
            free_node(ren[j*x_times+i]);
        }

    }
    free(ren);
    return re;
}
static inline void test_make_up_file(const char* filename)
{
    Mesh mesh;
    Mesh_init(&mesh);
    _Read_(&mesh,filename);


    Points_Cloud_Analyzer*pca= points_cloud_analyze_points_from_mesh(&mesh);
    float * data=test_make_up_points(&mesh,pca->xs[0],pca->xs[1],pca->ys[0],pca->ys[1],400,400); 

    free(data);

    points_cloud_analyzer_free(pca);
    Mesh_free(&mesh);
}
int main()
{

    test_make_up_file("11.obj"); 
    //float * data=test_make_up_points("09031.off",-737.0,32591.0,0.0,23099.60,400,400); 
    

//    float * data=test_make_up_points("11.obj",-46600.0,38.0,-16669.0,200165.00,400,400); 
  //  free(data);
    
    return 0;
}
